﻿using SuperWebSocket.SubProtocol;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using JmShared;
using System.Diagnostics;
using System.Threading;
using SuperSocket.SocketBase;
using WebSocketServer.models;
using System.Collections.Concurrent;
using WebSocketServer.Utilities;
using WebSocketServer.Filters;

namespace WebSocketServer.Commands
{
    [LogTimeCommandFilter(Order = 0)]
    public class Login : JsonSubCommand<JiveClientSession, LoginRequest>
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger
(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        protected override void ExecuteJsonCommand(JiveClientSession session, LoginRequest loginInfo)
        {
            try
            {
                if (loginInfo == null) throw new ArgumentNullException("loginInfo", "loginInfo is null");

                ServerInfoMessage msg = new ServerInfoMessage();
                DeviceType deviceType = SharedStaticMethods.GetDeviceType(loginInfo.UserInfo.UserID);
                var result = DB.DbManager.LoginCheck(loginInfo.UserName, loginInfo.Password);
                bool loginOK = result.Success;
                if (!loginOK)
                {
                    try
                    {
                        LoginResponse errorResponse = null;
                        string errorTxt = "Wrong username or password";
                        switch (deviceType)
                        {
                            case DeviceType.other:
                            case DeviceType.PC:
                                errorResponse = new PcLoginResponse(errorTxt);
                                break;
                            case DeviceType.Android:
                                errorResponse = new AndroidLoginResponse(errorTxt);
                                break;
                            case DeviceType.WindowsPhone:
                                errorResponse = new PcLoginResponse(errorTxt);
                                break;
                        }
                        session.SendLoginResponse(errorResponse);
                    }
                    catch (Exception err)
                    {
                        log.Error("Error sending error response", err);
                    }

                    //// Set is never called, so we wait always until the timeout occurs
                    //using (EventWaitHandle tmpEvent = new ManualResetEvent(false))
                    //{
                    //    tmpEvent.WaitOne(TimeSpan.FromMilliseconds(100));
                    //}

                    session.Close(CloseReason.ServerClosing);
                    return;
                }

       

                if (deviceType == DeviceType.PC)
                {
                    bool? isValidVersion = ValidateVersion(loginInfo.ClientVersion);
                    if (isValidVersion.HasValue && isValidVersion.Value == false)
                    {
                        try
                        {
                            LoginResponse errorResponse = null;
                            string errorTxt = "Please update to the most recent client.";
                            switch (deviceType)
                            {
                                case DeviceType.other:
                                case DeviceType.PC:
                                    errorResponse = new PcLoginResponse(errorTxt);
                                    break;
                                case DeviceType.Android:
                                    errorResponse = new AndroidLoginResponse(errorTxt);
                                    break;
                                case DeviceType.WindowsPhone:
                                    errorResponse = new PcLoginResponse(errorTxt);
                                    break;
                            }
                            session.SendLoginResponse(errorResponse);
                        }
                        catch (Exception err)
                        {
                            log.Error("Error sending error response", err);
                        }


                        session.Close(CloseReason.ServerClosing);
                        return;
                    }
                }

                UserInfo sender = loginInfo.UserInfo;

                ChatClient client = new ChatClient(sender, session, deviceType, (int)result.Value);
                client.ClientVersion = Int32.Parse(loginInfo.ClientVersion.Replace(".", ""));
                if (loginInfo.TimezoneOffset.HasValue)
                    client.TimeZoneOffset = loginInfo.TimezoneOffset.Value;
                Clients.AddConnectedClient(session, client);

                session.IsLoggedIn = true;
                session.ChatClient = client;

                ClientList clientList = session.ChatClient.CreateClientList();
                LoginResponse response = null;
                switch (session.ChatClient.DeviceType)
                {
                    case DeviceType.other:
                    case DeviceType.PC:
                        response = new PcLoginResponse(client.Username, clientList, client.UserSettings as PcUserSettings);
                        break;
                    case DeviceType.Android:
                        response = new AndroidLoginResponse(client.Username, clientList, client.UserSettings as AndroidUserSettings);
                        break;
                    case DeviceType.WindowsPhone:
                        client.IsActive = true;
                        response = new WinRTLoginResponse(client.Username, clientList, client.UserSettings as WpUserSettings);
                        break;
                }

                try
                {
                    session.SendLoginResponse(response);
                }
                catch (Exception err)
                {
                    log.Error("Error sending login response", err);
                    throw;//we want to stop at this point, as something went wrong in the login response.
                }

                client.UpdateNotifications(false);
                client.UpdateDeviceSync(client.LastMessageSyncTime,true,true);
            }
            catch (Exception err)
            {
                log.Error("Exception in ProcessLogin", err);
                session.Close(CloseReason.ApplicationError);
            }
        }


        private bool? ValidateVersion(string version)
        {
            //   Stopwatch watch = Stopwatch.StartNew();
            if (String.IsNullOrEmpty(version))
                return null;
            try
            {
                int clientVer = Int32.Parse(version.Replace(".", ""));
                string versionString = System.Configuration.ConfigurationManager.AppSettings["LastSupportedClientVersion"];

                int lastSupportedVer = String.IsNullOrEmpty(versionString) ? 0 : Int32.Parse(versionString.Replace(".", ""));

                // WriteLog("Time for validate version: " + watch.ElapsedMilliseconds + "ms");
                return clientVer >= lastSupportedVer;

            }
            catch (Exception err)
            {
                log.Error("Error parsing client version", err);
                return false;
            }
        }
    }
}
